﻿/*
 * @Autor: PK
 * @Date: 2021/12/24 17:17:SS
 */

using System;
using System.Collections.Generic;
using GeneticAlgorithm.Components.Interfaces;
using GeneticAlgorithm.Interfaces;
using ShkSimulation.core.exceptions;
using ShkSimulation.core.optimization.variable;

namespace ShkSimulation.core.optimization.algorithm.classicGeneticAlgotithm {


	public class DoublePopulationGenerator : IPopulationGenerator {

		private readonly Random random = new Random();
		private DecisionVariableVector<double> variables;
		private double[] range;
		private readonly int vectorSize;
		private readonly IMutationManager<double> mutationManager;
		private readonly IEvaluator evaluator;

		public DoublePopulationGenerator(
			DecisionVariableVector<double> decisionVariables,  
			IMutationManager<double> mutationManager,
			IEvaluator evaluator) {
			if (decisionVariables == null || decisionVariables.Length == 0)
				throw new ErrorParamException($"{nameof(decisionVariables)} must be bigger than 0");
			this.vectorSize = decisionVariables.Length;
			this.variables = decisionVariables;
			this.mutationManager = mutationManager;
			this.evaluator = evaluator;
			this.range = new double[decisionVariables.Length];
			for (int i = 0; i < decisionVariables.Length; i++) {
				range[i] = decisionVariables[i].UpperBound - decisionVariables[i].LowerBound;
			}
		}

		public IEnumerable<IChromosome> GeneratePopulation(int size) {
			IChromosome[] population = new IChromosome[vectorSize];
			for (int index = 0; index < vectorSize; ++index)
				population[index] = this.GetChromosome();
			return population;
		}

		private NamedVectorChromosome<double> GetChromosome() {
			Dictionary<string, double> result = new Dictionary<string, double>();
			for (int index = 0; index < this.vectorSize; ++index) {
				double temp = variables[index].LowerBound + this.random.NextDouble() * range[index];
				result.Add(variables[index].Name, temp);
			}
			return new NamedVectorChromosome<double>(result, this.mutationManager, this.evaluator);
		}
	}

}